package com.ops.uitl.jdbc;

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.Statement;
import oracle.jdbc.OraclePreparedStatement;
import org.apache.log4j.Logger;
import com.ops.uitl.data.IData;
import com.ops.uitl.data.IDataset;

public class OracleParameterStatement implements IStatement {

	protected final Logger log = Logger.getLogger(this.getClass());
	
	private OraclePreparedStatement statement;
	private String sql;
	private IData param;
	private IDataset params;
	
	/**
	 * construct function
	 * @param conn
	 * @param sql
	 * @param param
	 * @throws Exception
	 */
	public OracleParameterStatement(Connection conn, String sql, IData param) throws Exception {
		statement = (OraclePreparedStatement) conn.prepareStatement(sql);
		this.sql = sql;
		this.param = param;
	}
	
	/**
	 * construct function
	 * @param conn
	 * @param sql
	 * @param params
	 * @throws Exception
	 */
	public OracleParameterStatement(Connection conn, String sql, IDataset params) throws Exception {
		statement = (OraclePreparedStatement) conn.prepareStatement(sql);
		this.sql = sql;
		this.params = params;
	}
		
	/**
	 * get sql
	 * @return String
	 * @throws Exception
	 */
    public String getSql() throws Exception {
    	return sql;
    }

	/**
	 * get statement
	 * @return Statement
	 * @throws Exception
	 */
    public Statement getStatement() throws Exception {
    	return statement;
    }

	/**
	 * execute query
	 * @return ResultSet
	 * @throws Exception
	 */
    public ResultSet executeQuery() throws Exception {
    	if (log.isDebugEnabled()) log.debug("SQL " + sql);
    	if (log.isDebugEnabled()) log.debug("PARAM " + param);
    	
    	setParameters(statement, param);
    	
    	try {
    		long beginTime = System.currentTimeMillis();
    		ResultSet result = statement.executeQuery();
    		DaoHelper.getExecuteTimeBySql(log, beginTime);
    		return result;
    	} catch (java.sql.SQLException e) {
    		log.error("ERROR SQL " + sql);
    		throw e;
    	}
    }
    
    /**
     * execute update
     * @return int
     * @throws Exception
     */
    public int executeUpdate() throws Exception {
    	if (log.isDebugEnabled()) log.debug("SQL " + sql);
    	if (log.isDebugEnabled()) log.debug("PARAM " + param);
    	
    	setParameters(statement, param);
    	
    	try {
    		long beginTime = System.currentTimeMillis();
    		int result = statement.executeUpdate();
    		DaoHelper.getExecuteTimeBySql(log, beginTime);
    		return result;
    	} catch (java.sql.SQLException e) {
    		log.error("ERROR SQL " + sql);
    		throw e;
    	}
    }
    
    /**
     * execute batch
     * @return int[]
     * @throws Exception
     */
    public int[] executeBatch() throws Exception {
    	if (params.size() == 0) return new int[] {};
    	
    	if (log.isDebugEnabled()) log.debug("Batch SQL " + sql);
    	
    	for (int i=0; i<params.size(); i++) {
    		setParameters(statement, (IData) params.get(i));
    		if (log.isDebugEnabled()) log.debug("PARAM " + params.get(i));
    		statement.addBatch();
    	}
    	
    	try {
	    	long beginTime = System.currentTimeMillis();
	    	int[] result = statement.executeBatch();
	    	DaoHelper.getExecuteTimeBySql(log, beginTime);
	    	return result;
    	} catch (java.sql.SQLException e) {
    		log.error("ERROR Batch SQL " + sql);
    		throw e;
    	}
    }

	/**
	 * close statement
	 * @throws Exception
	 */
	public void close() throws Exception {
		statement.close();
	}
	
	/**
	 * set parameters
	 * @param statement
	 * @param param
	 * @throws Exception
	 */
	public void setParameters(OraclePreparedStatement statment, IData param) throws Exception {
    	String[] names= param.getNames();
		for (int i=0; i<names.length; i++) {
			String name = names[i];
			Object value = param.get(name);
			if (value instanceof String) {
	    		try {
	    			statement.setObjectAtName(name, value);
	    		} catch (Exception e) {
	    			if (log.isDebugEnabled()) log.debug("column " + name + " not bound!");
	    		}
			}
    	}
	}
	
}